package com.ts.api.module.channel.service.impl;

import com.gitee.apanlh.util.algorithm.digest.MD5;
import com.gitee.apanlh.util.base.CollUtils;
import com.gitee.apanlh.util.base.Eq;
import com.gitee.apanlh.util.base.IteratorUtils;
import com.gitee.apanlh.util.dataformat.JsonUtils;
import com.gitee.apanlh.util.date.DateUtils;
import com.gitee.apanlh.util.log.Log;
import com.gitee.apanlh.util.valid.Assert;
import com.gitee.apanlh.util.valid.ValidParam;
import com.ts.api.common.constant.BizEnum;
import com.ts.api.common.constant.api.ApiEnum;
import com.ts.api.common.constant.product.ProductPlanOrgTypeEnum;
import com.ts.api.common.constant.product.ProductPlanTypeEnum;
import com.ts.api.common.constant.product.ProductPlanVersionEnum;
import com.ts.api.common.constant.product.ProductPlanVersionMode;
import com.ts.api.common.constant.productflow.ProductApplyFlowSrcTypeEnum;
import com.ts.api.common.constant.productflow.ProductApplyFlowStatusEnum;
import com.ts.api.common.constant.protocol.UserProtocolEnum;
import com.ts.api.common.context.ChannelContext;
import com.ts.api.common.context.ChannelUserContext;
import com.ts.api.common.localcache.DistrictCache;
import com.ts.api.common.redis.ApiMatchPhoneMaskRedisKey;
import com.ts.api.common.redis.entity.ApiMatchPhoneMaskRedisCache;
import com.ts.api.common.util.H5DomainUrlUtils;
import com.ts.api.exp.ApiMsgException;
import com.ts.api.exp.BizException;
import com.ts.api.module.api.convert.core.http.client.ApiHttpMessage;
import com.ts.api.module.api.convert.plan.http.ApiPlanHttpHandler;
import com.ts.api.module.api.convert.platform.context.ApiPlatformConvertContext;
import com.ts.api.module.api.convert.platform.entity.RespPlatformMultiPhoneMaskDataExchange;
import com.ts.api.module.api.convert.platform.entity.RespPlatformPhoneMaskDataExchange;
import com.ts.api.module.api.convert.platform.entity.RespPlatformPhoneMd5Apply;
import com.ts.api.module.api.convert.platform.entity.RespPlatformPhoneMd5DataExchange;
import com.ts.api.module.api.convert.platform.handler.ApiPlatformPhoneMd5ConvertHandler;
import com.ts.api.module.api.entity.ApiUserRequest;
import com.ts.api.module.api.entity.bo.ApiBizMatchBO;
import com.ts.api.module.api.entity.bo.ApiRequiredFlowBO;
import com.ts.api.module.api.service.ApiBizRequiredService;
import com.ts.api.module.api.service.ApiUserRegister;
import com.ts.api.module.channel.entity.bo.ChannelProductMatchApplyBO;
import com.ts.api.module.channel.entity.bo.ChannelProductMatchBO;
import com.ts.api.module.channel.entity.bo.ChannelProductMatchDisplayBO;
import com.ts.api.module.channel.entity.cache.ChannelCacheUser;
import com.ts.api.module.channel.entity.po.ChannelPO;
import com.ts.api.module.channel.entity.po.ChannelUserFormFieldPO;
import com.ts.api.module.channel.entity.po.ChannelUserRegisterPO;
import com.ts.api.module.channel.entity.qo.ChannelUserQO;
import com.ts.api.module.channel.service.ChannelConfigService;
import com.ts.api.module.channel.service.ChannelFormService;
import com.ts.api.module.channel.service.ChannelProductMatchService;
import com.ts.api.module.channel.service.ChannelUserService;
import com.ts.api.module.common.entity.DistrictPO;
import com.ts.api.module.common.service.SmsService;
import com.ts.api.module.match.plan.PlanDataExchangeFacade;
import com.ts.api.module.match.plan.internal.distribute.model.PlanDistributeField;
import com.ts.api.module.match.plan.internal.distribute.model.PlanDistributePhoneMaskField;
import com.ts.api.module.match.plan.internal.distribute.model.PlanDistributePhoneMd5Field;
import com.ts.api.module.match.plan.internal.distribute.model.PlanDistributeResult;
import com.ts.api.module.match.plan.internal.qualification.model.PlanQualificationError;
import com.ts.api.module.match.plan.internal.qualification.model.PlanQualificationResult;
import com.ts.api.module.match.plan.model.ChannelPlanMatch;
import com.ts.api.module.product.entity.bo.ProductAmountBO;
import com.ts.api.module.product.entity.po.ProductApplyFlowPO;
import com.ts.api.module.product.entity.po.ProductPO;
import com.ts.api.module.product.entity.po.ProductPlanPO;
import com.ts.api.module.product.service.ProductAmountService;
import com.ts.api.module.product.service.ProductPlanService;
import com.ts.api.module.product.service.ProductPlanTypeService;
import com.ts.api.module.product.service.ProductService;
import com.ts.api.module.protocol.entity.po.ProductProtocolPO;
import com.ts.api.module.protocol.entity.po.UserProtocolPO;
import com.ts.api.module.protocol.entity.qo.ProductProtocolQO;
import com.ts.api.module.protocol.service.ProductProtocolService;
import com.ts.api.module.protocol.service.UserProtocolService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;

@Service
public class ChannelProductMatchServiceImpl implements ChannelProductMatchService {

    @Autowired
    private ChannelFormService channelFormService;
    @Autowired
    private ChannelUserService channelUserService;
    @Autowired
    private ProductPlanTypeService productPlanTypeService;
    @Autowired
    private ProductService productService;
    @Autowired
    private ProductPlanService productPlanService;
    @Autowired
    private ApiBizRequiredService apiBizRequiredService;
    @Autowired
    private ProductAmountService productAmountService;
    @Autowired
    private ApiPlanHttpHandler apiPlanHttpHandler;
    @Autowired
    private ProductProtocolService productProtocolService;
    @Autowired
    private UserProtocolService userProtocolService;
    @Autowired
    private SmsService smsService;
    @Autowired
    private ApiUserRegister apiUserRegister;
    @Autowired
    private ApiPlatformConvertContext apiPlatformConvertContext;
    @Autowired
    private PlanDataExchangeFacade planDataExchangeFacade;
    @Autowired
    private ChannelConfigService channelConfigService;

    @Override
    public ChannelProductMatchBO dataExchange(ApiBizMatchBO apiBizMatchBO, boolean onlyMatchAll) {
        ChannelProductMatchBO channelProductMatchBO = new ChannelProductMatchBO();
        ChannelPO channelPO = ChannelContext.get();
        ChannelCacheUser channelUser = ChannelUserContext.get();

        //  匹配计划类型
        List<ProductPlanTypeEnum> listPlanType = apiBizMatchBO.getListPlanType();

        //  获取用户信息
        ChannelUserRegisterPO channelUserRegisterPO = channelUserService.get(ChannelUserQO.createPhone(channelUser.getPhone()));

        //  获取用户表单
        List<ChannelUserFormFieldPO> listUserFormField = channelFormService.listUserFormField();
        Assert.isNotEmptyThrows(listUserFormField, new BizException(BizEnum.MATCH_USER_EMPTY));

        //  匹配计划
        ChannelPlanMatch channelPlanMatch = ChannelPlanMatch.ofMatch(channelPO, channelUserRegisterPO, listUserFormField, listPlanType);
        PlanQualificationResult planQualificationResult = planDataExchangeFacade.searchDistributePlan(channelPlanMatch, productPlanPO -> {
            //  只匹配全流程
            if (onlyMatchAll) {
                if (ProductPlanOrgTypeEnum.ENTERPRISE_WECHAT.hasType(productPlanPO.getType())) {
                    return true;
                }
                return !ProductPlanVersionEnum.ALL.hasVersion(productPlanPO.getVersionType())
                        && !ProductPlanVersionEnum.IGNORE.hasVersion(productPlanPO.getVersionType());
            }
            return false;
        });

        //  抛出错误信息
        PlanQualificationError planQualificationError = planQualificationResult.getValidateFail();
        if (ValidParam.isNotNull(planQualificationError)) {
            Log.get().error("自有渠道分发异常:{}", planQualificationError.getErrorMsg(), planQualificationError.getExp());
            return channelProductMatchBO;
        }

        //  无分发结果
        PlanDistributeResult planDistributeResult = planDataExchangeFacade.channelDataExchange(planQualificationResult);
        if (!planDistributeResult.getDistributeStatus()) {
            return channelProductMatchBO;
        }

        //  获取最终匹配结果
        ProductPO productPO = planDistributeResult.getProductPO();
        ProductPlanPO productPlanPO = planDistributeResult.getProductPlanPO();
        PlanDistributeField planDistributeField = planDistributeResult.getPlanDistributeField();

        //  获取返回字段参数
        ChannelProductMatchDisplayBO channelProductMatchDisplayBO = new ChannelProductMatchDisplayBO();
        {
            //  md5模式
            PlanDistributePhoneMd5Field phoneMd5Field = planDistributeField.getPhoneMd5Field();
            if (ValidParam.isNotNull(phoneMd5Field)) {
                //  订单号id
                channelProductMatchDisplayBO.setApplyId(phoneMd5Field.getApplyId());
                //  半流程url
                channelProductMatchDisplayBO.setCallUrl(phoneMd5Field.getCallUrl());
                //  主体名称
                channelProductMatchDisplayBO.setProductName(phoneMd5Field.getProductName());
                //  投放名称
                channelProductMatchDisplayBO.setDisplayName(phoneMd5Field.getDisplayName());
                //  logo
                channelProductMatchDisplayBO.setLogoPath(phoneMd5Field.getLogoPath());
            }
        }

        {
            //  掩码模式-获取首条
            List<PlanDistributePhoneMaskField> listPhoneMaskField = planDistributeField.getListPhoneMaskField();
            if (ValidParam.isNotEmpty(listPhoneMaskField)) {
                PlanDistributePhoneMaskField firstPhoneMaskField = listPhoneMaskField.getFirst();
                //  订单号id
                channelProductMatchDisplayBO.setApplyId(firstPhoneMaskField.getApplyId());
                //  半流程url
                channelProductMatchDisplayBO.setCallUrl(firstPhoneMaskField.getCallUrl());
                //  主体名称
                channelProductMatchDisplayBO.setProductName(firstPhoneMaskField.getProductName());
                //  投放名称
                channelProductMatchDisplayBO.setDisplayName(firstPhoneMaskField.getDisplayName());
                //  logo
                channelProductMatchDisplayBO.setLogoPath(firstPhoneMaskField.getLogoPath());
            }
        }

        channelProductMatchBO.setProductPO(productPO);
        channelProductMatchBO.setProductPlanPO(productPlanPO);
        channelProductMatchBO.setChannelProductMatchDisplayBO(channelProductMatchDisplayBO);
        channelProductMatchBO.setDistributeStatus(true);
        return channelProductMatchBO;
    }

    @Override
    public ChannelProductMatchApplyBO apply() {
        ChannelPO channelPO = ChannelContext.get();
        ChannelCacheUser channelUser = ChannelUserContext.get();

        Long loanChannelId = channelPO.getId();
        String phone = channelUser.getPhone();

        //  获取撞库流程记录
        ApiRequiredFlowBO apiRequiredFlowBO = ApiRequiredFlowBO.createByChannelId(MD5.create().digestToHex(phone), loanChannelId);
        ProductApplyFlowPO productApplyFlowPO = apiBizRequiredService.requiredSucDataExchangeFlow(apiRequiredFlowBO);
        Assert.isNotNullThrows(productApplyFlowPO, new BizException(BizEnum.MATCH_APPLY_FLOW_ERROR));

        //  获取主体计划
        ProductPlanPO productPlanPO = productPlanService.get(productApplyFlowPO.getLoanProductPlanId());

        //  获取主体信息
        ProductPO productPO = productService.get(productApplyFlowPO.getLoanProductId());

        //  获取用户信息
        ChannelUserQO channelUserQOByPhone = ChannelUserQO.createPhone(phone);
        ChannelUserRegisterPO channelUserRegisterPO = channelUserService.get(channelUserQOByPhone);

        //  获取用户资质
        Long userId = channelUserRegisterPO.getId();
        List<ChannelUserFormFieldPO> listUserField = channelFormService.listUserFormField(userId);

        //  获取地区
        String areaName = channelUserRegisterPO.getAreaName();
        DistrictPO districtPO = DistrictCache.getByName(areaName);

        //  获取API传输对象
        ApiUserRequest apiUserRequest = ApiUserRequest.convert(channelUserRegisterPO, listUserField);
        apiUserRequest.setAreaCode(districtPO.getCode());
        apiUserRequest.setProvinceCode(districtPO.getProvinceCode());
        apiUserRequest.setProvinceName(districtPO.getProvinceName());

        //  记录流程
        ProductApplyFlowPO insertProductApplyFlowPO = new ProductApplyFlowPO();
        insertProductApplyFlowPO.setApiClientId(productApplyFlowPO.getApiClientId());
        insertProductApplyFlowPO.setLoanChannelId(productApplyFlowPO.getLoanChannelId());
        insertProductApplyFlowPO.setLoanProductId(productApplyFlowPO.getLoanProductId());
        insertProductApplyFlowPO.setLoanProductPlanId(productApplyFlowPO.getLoanProductPlanId());
        insertProductApplyFlowPO.setReqId(productApplyFlowPO.getReqId());
        insertProductApplyFlowPO.setSrcType(ProductApplyFlowSrcTypeEnum.API.getType());
        insertProductApplyFlowPO.setStatus(ProductApplyFlowStatusEnum.APPLY_ERROR.getType());
        insertProductApplyFlowPO.setPhoneMd5(productApplyFlowPO.getPhoneMd5());
        insertProductApplyFlowPO.setCreateTime(DateUtils.currentTime());
        insertProductApplyFlowPO.setBizStatus("0");
        insertProductApplyFlowPO.setAreaName(apiUserRequest.getCity());
        insertProductApplyFlowPO.setAreaCode(apiUserRequest.getAreaCode());

        //  空号检测
        boolean requiredPhoneStatus = apiBizRequiredService.requiredPhoneStatus(insertProductApplyFlowPO, productPlanPO, channelUserRegisterPO.getPhone());
        if (!requiredPhoneStatus) {
            throw new ApiMsgException(ApiEnum.API_RECEIVE_ORG_ERROR);
        }

        //  是否本地机构计划
        if (productPlanTypeService.hasLocalOrgPlan(productPO, productPlanPO)) {
            insertProductApplyFlowPO.setCallUrl("本地甲方CRM");
        }

        //  API机构计划或平台计划
        boolean hasPlatform = productPlanTypeService.hasPlatformPlan(productPlanPO);
        boolean hasApiOrgPlan = productPlanTypeService.hasApiOrgPlan(productPO, productPlanPO);

        //  返回对象
        ChannelProductMatchApplyBO channelProductMatchApplyBO = new ChannelProductMatchApplyBO();

        if (hasPlatform || hasApiOrgPlan) {
            Long reqId = insertProductApplyFlowPO.getReqId();

            //  获取进件applyId值
            String saveApplyKey = ApiMatchPhoneMaskRedisKey.getChannelDataExchangeApplyIdKey(loanChannelId, productPO.getId(), productPlanPO.getId(), productApplyFlowPO.getPhoneMd5());
            ApiMatchPhoneMaskRedisCache apiMatchPhoneMaskRedisCache = ApiMatchPhoneMaskRedisKey.CHANNEL_DATA_EXCHANGE_PHONE_MASK_APPLY_ID.get(saveApplyKey, ApiMatchPhoneMaskRedisCache.class);
            if (ValidParam.isNotNull(apiMatchPhoneMaskRedisCache)){
                String applyId = apiMatchPhoneMaskRedisCache.getApplyId();
                apiUserRequest.setApplyId(applyId);
            }

            //  设置API参数数据
            apiUserRequest.setProductId(insertProductApplyFlowPO.getLoanProductId());
            apiUserRequest.setProductPlanId(insertProductApplyFlowPO.getLoanProductPlanId());
            apiUserRequest.setLoanChannelId(insertProductApplyFlowPO.getLoanChannelId());
            apiUserRequest.setReqId(reqId.toString());

            //  发送进件
            ApiHttpMessage httpMessage = apiPlanHttpHandler.sendApply(apiUserRequest, productPO, productPlanPO);
            insertProductApplyFlowPO.setCallUrl(productPO.getApiApplyUrl());
            insertProductApplyFlowPO.setSourceReqData(httpMessage.getSourceRequestBody());
            insertProductApplyFlowPO.setReqData(String.valueOf(httpMessage.getRequestBody()));
            insertProductApplyFlowPO.setRespData(httpMessage.getResponseBody());
            insertProductApplyFlowPO.setRespCode(String.valueOf(httpMessage.getRespCode()));

            //  是否返回HTTP异常
            boolean hasHttpExp = apiBizRequiredService.hasHttpExp(insertProductApplyFlowPO, httpMessage, true, ProductApplyFlowStatusEnum.APPLY_ERROR);
            if (hasHttpExp) {
                throw new ApiMsgException(ApiEnum.API_RECEIVE_ORG_ERROR);
            }

            //  是否进件返回失败
            boolean hasHttpRespBizSuc = apiBizRequiredService.hasHttpRespBizSuc(insertProductApplyFlowPO, httpMessage, true, ProductApplyFlowStatusEnum.APPLY_ERROR);
            if (!hasHttpRespBizSuc) {
                throw new ApiMsgException(ApiEnum.API_RECEIVE_ORG_FAIL);
            }

            //  记录下游用户协议
            if (hasPlatform) {
                ProductProtocolQO productProtocolQO = new ProductProtocolQO();
                productProtocolQO.setProductId(productApplyFlowPO.getLoanProductId());
                productProtocolQO.setHasNeedText(true);
                List<ProductProtocolPO> listProductProtocol = productProtocolService.list(productProtocolQO);

                //  添加下游协议
                IteratorUtils.array(listProductProtocol, productProtocolPO -> {
                    String productTemplate = productProtocolPO.getText();
                    String phoneMd5 = channelUserRegisterPO.getPhoneMd5();

                    //  查询平台模板
                    UserProtocolPO userProtocolPO = new UserProtocolPO();
                    userProtocolPO.setLoanChannelId(productApplyFlowPO.getLoanChannelId());
                    userProtocolPO.setLoanProductId(productApplyFlowPO.getLoanProductId());
                    userProtocolPO.setLoanProductPlanId(productApplyFlowPO.getLoanProductPlanId());
                    userProtocolPO.setLoanProductProtocolId(productProtocolPO.getId());
                    userProtocolPO.setLoanUserId(channelUserRegisterPO.getId());
                    userProtocolPO.setPhoneMd5(phoneMd5);
                    userProtocolPO.setUrl(H5DomainUrlUtils.createUserProtocolUrl(productApplyFlowPO.getLoanProductPlanId(), phoneMd5));
                    userProtocolPO.setType(UserProtocolEnum.PRODUCT.getType());
                    userProtocolPO.setCreateTime(DateUtils.currentTime());

                    //  填充协议模板
                    //  md5模式
                    if (ProductPlanVersionMode.MD5.hasVersionMode(productPlanPO)) {
                        RespPlatformPhoneMd5DataExchange md5DataExchange = RespPlatformPhoneMd5DataExchange.parseByJson(productApplyFlowPO.getRespData());
                        String appendedTemplate = userProtocolService.appendTemplate(channelUserRegisterPO, productTemplate, md5DataExchange);
                        userProtocolPO.setText(appendedTemplate);
                        userProtocolService.insert(userProtocolPO);
                    }

                    //  掩码模式
                    if (Eq.objectOr(productPlanPO.getVersionMode(),
                            ProductPlanVersionMode.PHONE_MASK_8.getVersionMode(),
                            ProductPlanVersionMode.PHONE_MASK_9.getVersionMode(),
                            ProductPlanVersionMode.PHONE_MASK_10.getVersionMode())) {

                        //  填充模板
                        RespPlatformMultiPhoneMaskDataExchange respMultiPhoneMask = JsonUtils.toBean(productApplyFlowPO.getRespData(), RespPlatformMultiPhoneMaskDataExchange.class);
                        String applyId = apiUserRequest.getApplyId();
                        //  获取原始撞库apply对应进件apply数据
                        List<RespPlatformPhoneMaskDataExchange> listPhoneMask = respMultiPhoneMask.getListPhoneMask();
                        RespPlatformPhoneMaskDataExchange findPhoneMask = CollUtils.findOne(listPhoneMask, phoneMaskDataExchange -> phoneMaskDataExchange.getApplyId().equals(applyId));

                        String appendedTemplate = userProtocolService.appendTemplatePhoneMask(channelUserRegisterPO, productTemplate, findPhoneMask);
                        userProtocolPO.setText(appendedTemplate);
                        userProtocolService.insert(userProtocolPO);
                    }
                });

                //  进件返回url模式
                if (ProductPlanVersionMode.MD5.hasVersionMode(productPlanPO)) {
                    ApiPlatformPhoneMd5ConvertHandler platFromPhoneMd5 = apiPlatformConvertContext.getPlatformPhoneMd5(productPlanPO);
                    if (ValidParam.isNotNull(platFromPhoneMd5)) {
                        try {
                            RespPlatformPhoneMd5Apply respPlatformPhoneMd5Apply = platFromPhoneMd5.respApply(httpMessage.getResponseBody());
                            String callUrl = respPlatformPhoneMd5Apply.getCallUrl();
                            channelProductMatchApplyBO.setUrl(callUrl);
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            }
        }

        //  用户数据关联机构并记录流程数据
        insertProductApplyFlowPO.setStatus(ProductApplyFlowStatusEnum.USER_ACCEPT.getType());
        insertProductApplyFlowPO.setBizStatus("1");
        //  分发的是本地CRM已经有件时则返回进件失败，只要一次件
        if (productPlanTypeService.hasLocalOrgPlan(productPO, productPlanPO)) {
            try {
                apiUserRegister.uniqueBindProductUser(insertProductApplyFlowPO, channelUserRegisterPO.getId());
            } catch (Exception e) {
                throw new ApiMsgException(ApiEnum.API_USER_INFO_EXIST.format("进件"));
            }
        } else {
            //  如果分发的是平台/API机构计划则忽略限制
            apiUserRegister.multiBindProductUser(insertProductApplyFlowPO, channelUserRegisterPO.getId());
        }

        //  主体-单次计费业务
        BigDecimal originalPrice = null;
        //  平台计划解析撞库成功时的单价
        if (hasPlatform) {
            //  md5模式
            if (ProductPlanVersionMode.MD5.hasVersionMode(productPlanPO)) {
                RespPlatformPhoneMd5DataExchange md5DataExchange = RespPlatformPhoneMd5DataExchange.parseByJson(productApplyFlowPO.getRespData());
                originalPrice = md5DataExchange.getPrice();
            }

            //  掩码模式
            if (Eq.objectOr(productPlanPO.getVersionMode(),
                ProductPlanVersionMode.PHONE_MASK_8.getVersionMode(),
                ProductPlanVersionMode.PHONE_MASK_9.getVersionMode(),
                ProductPlanVersionMode.PHONE_MASK_10.getVersionMode())) {

                //  找到原始进件applyId
                String applyId = apiUserRequest.getApplyId();

                RespPlatformMultiPhoneMaskDataExchange respMultiPhoneMask = JsonUtils.toBean(productApplyFlowPO.getRespData(), RespPlatformMultiPhoneMaskDataExchange.class);
                List<RespPlatformPhoneMaskDataExchange> listPhoneMask = respMultiPhoneMask.getListPhoneMask();

                //  获取原始撞库apply对应进件apply数据
                RespPlatformPhoneMaskDataExchange findPhoneMaskDataExchange =
                        CollUtils.findOne(listPhoneMask, phoneMaskDataExchange -> phoneMaskDataExchange.getApplyId().equals(applyId));
                originalPrice = findPhoneMaskDataExchange.getPrice();
            }
        }

        ProductAmountBO productAmountBO = new ProductAmountBO();
        productAmountBO.setProductId(productPlanPO.getLoanProductId());
        productAmountBO.setProductPlanId(productPlanPO.getId());
        productAmountBO.setUserId(channelUserRegisterPO.getId());
        productAmountBO.setPhoneMd5(channelUserRegisterPO.getPhoneMd5());
        productAmountBO.setLoanChannelId(productApplyFlowPO.getLoanChannelId());
        productAmountBO.setApiClientId(productApplyFlowPO.getApiClientId());
        productAmountBO.setOriginalPrice(originalPrice);
        productAmountBO.setHasPlatform(hasPlatform);
        productAmountBO.setHasLocalExist(Boolean.FALSE);
        productAmountService.deduct(productAmountBO);

        //  发送短信-非平台才发送短信
        if (!hasPlatform) {
            //  符合IP屏蔽 需发送特定的短信
            if (channelConfigService.hasIpOffModule()) {
                smsService.sendCustomerNoticeForIpOffModule(phone, productPlanPO.getDisplayName());
            } else {
                smsService.sendCustomerNotice(phone, productPlanPO.getDisplayName());
            }
        }

        return channelProductMatchApplyBO;
    }

    @Override
    public void callbackNoticeApply(ProductPO productPO, ProductPlanPO productPlanPO, ProductApplyFlowPO productApplyFlowPO, String phoneMd5) {
        //  获取用户信息
        ChannelUserQO channelUserQOByPhone = ChannelUserQO.createPhoneMd5(phoneMd5);
        ChannelUserRegisterPO channelUserRegisterPO = channelUserService.get(channelUserQOByPhone);
        String phone = channelUserRegisterPO.getPhone();

        //  获取用户资质
        Long userId = channelUserRegisterPO.getId();
        List<ChannelUserFormFieldPO> listUserField = channelFormService.listUserFormField(userId);

        //  获取地区
        String areaName = channelUserRegisterPO.getAreaName();
        DistrictPO districtPO = DistrictCache.getByName(areaName);

        //  获取API传输对象
        ApiUserRequest apiUserRequest = ApiUserRequest.convert(channelUserRegisterPO, listUserField);
        apiUserRequest.setAreaCode(districtPO.getCode());
        apiUserRequest.setProvinceCode(districtPO.getProvinceCode());
        apiUserRequest.setProvinceName(districtPO.getProvinceName());

        //  记录流程
        ProductApplyFlowPO insertProductApplyFlowPO = new ProductApplyFlowPO();
        insertProductApplyFlowPO.setApiClientId(productApplyFlowPO.getApiClientId());
        insertProductApplyFlowPO.setLoanChannelId(productApplyFlowPO.getLoanChannelId());
        insertProductApplyFlowPO.setLoanProductId(productApplyFlowPO.getLoanProductId());
        insertProductApplyFlowPO.setLoanProductPlanId(productApplyFlowPO.getLoanProductPlanId());
        insertProductApplyFlowPO.setReqId(productApplyFlowPO.getReqId());
        insertProductApplyFlowPO.setSrcType(ProductApplyFlowSrcTypeEnum.API.getType());
        insertProductApplyFlowPO.setStatus(ProductApplyFlowStatusEnum.APPLY_ERROR.getType());
        insertProductApplyFlowPO.setPhoneMd5(productApplyFlowPO.getPhoneMd5());
        insertProductApplyFlowPO.setCreateTime(DateUtils.currentTime());
        insertProductApplyFlowPO.setBizStatus("0");
        insertProductApplyFlowPO.setAreaName(apiUserRequest.getCity());
        insertProductApplyFlowPO.setAreaCode(apiUserRequest.getAreaCode());

        //  空号检测
        boolean requiredPhoneStatus = apiBizRequiredService.requiredPhoneStatus(insertProductApplyFlowPO, productPlanPO, channelUserRegisterPO.getPhone());
        if (!requiredPhoneStatus) {
            throw new ApiMsgException(ApiEnum.API_RECEIVE_ORG_ERROR);
        }

        //  是否本地机构计划
        if (productPlanTypeService.hasLocalOrgPlan(productPO, productPlanPO)) {
            insertProductApplyFlowPO.setCallUrl("本地甲方CRM");
        }

        //  API机构计划或平台计划
        boolean hasPlatform = productPlanTypeService.hasPlatformPlan(productPlanPO);
        boolean hasApiOrgPlan = productPlanTypeService.hasApiOrgPlan(productPO, productPlanPO);

        if (hasPlatform || hasApiOrgPlan) {
            Long reqId = insertProductApplyFlowPO.getReqId();
            //  设置API参数数据
            apiUserRequest.setProductId(insertProductApplyFlowPO.getLoanProductId());
            apiUserRequest.setProductPlanId(insertProductApplyFlowPO.getLoanProductPlanId());
            apiUserRequest.setLoanChannelId(insertProductApplyFlowPO.getLoanChannelId());
            apiUserRequest.setReqId(reqId.toString());

            //  发送进件
            ApiHttpMessage httpMessage = apiPlanHttpHandler.sendApply(apiUserRequest, productPO, productPlanPO);
            insertProductApplyFlowPO.setCallUrl(productPO.getApiApplyUrl());
            insertProductApplyFlowPO.setReqData(String.valueOf(httpMessage.getRequestBody()));
            insertProductApplyFlowPO.setRespData(httpMessage.getResponseBody());
            insertProductApplyFlowPO.setRespCode(String.valueOf(httpMessage.getRespCode()));

            //  是否返回HTTP异常
            boolean hasHttpExp = apiBizRequiredService.hasHttpExp(insertProductApplyFlowPO, httpMessage, true, ProductApplyFlowStatusEnum.APPLY_ERROR);
            if (hasHttpExp) {
                throw new ApiMsgException(ApiEnum.API_RECEIVE_ORG_ERROR);
            }

            //  是否进件返回失败
            boolean hasHttpRespBizSuc = apiBizRequiredService.hasHttpRespBizSuc(insertProductApplyFlowPO, httpMessage, true, ProductApplyFlowStatusEnum.APPLY_ERROR);
            if (!hasHttpRespBizSuc) {
                throw new ApiMsgException(ApiEnum.API_RECEIVE_ORG_FAIL);
            }

            //  记录下游用户协议
            if (hasPlatform) {
                ProductProtocolQO productProtocolQO = new ProductProtocolQO();
                productProtocolQO.setProductId(productApplyFlowPO.getLoanProductId());
                productProtocolQO.setHasNeedText(true);
                List<ProductProtocolPO> listProductProtocol = productProtocolService.list(productProtocolQO);

                //  添加下游协议
                IteratorUtils.array(listProductProtocol, productProtocolPO -> {
                    String productTemplate = productProtocolPO.getText();

                    //  查询平台模板
                    UserProtocolPO userProtocolPO = new UserProtocolPO();
                    userProtocolPO.setLoanChannelId(productApplyFlowPO.getLoanChannelId());
                    userProtocolPO.setLoanProductId(productApplyFlowPO.getLoanProductId());
                    userProtocolPO.setLoanProductPlanId(productApplyFlowPO.getLoanProductPlanId());
                    userProtocolPO.setLoanProductProtocolId(productProtocolPO.getId());
                    userProtocolPO.setLoanUserId(channelUserRegisterPO.getId());
                    userProtocolPO.setPhoneMd5(phoneMd5);
                    userProtocolPO.setUrl(H5DomainUrlUtils.createUserProtocolUrl(productApplyFlowPO.getLoanProductPlanId(), phoneMd5));
                    userProtocolPO.setType(UserProtocolEnum.PRODUCT.getType());
                    userProtocolPO.setCreateTime(DateUtils.currentTime());

                    //  填充模板
                    RespPlatformPhoneMd5DataExchange apiPlatFormDataExchange = RespPlatformPhoneMd5DataExchange.parseByJson(productApplyFlowPO.getRespData());
                    String appendedTemplate = userProtocolService.appendTemplate(channelUserRegisterPO, productTemplate, apiPlatFormDataExchange);
                    userProtocolPO.setText(appendedTemplate);
                    userProtocolService.insert(userProtocolPO);
                });
            }
        }

        //  用户数据关联机构并记录流程数据
        insertProductApplyFlowPO.setStatus(ProductApplyFlowStatusEnum.USER_ACCEPT.getType());
        insertProductApplyFlowPO.setBizStatus("1");
        apiUserRegister.uniqueBindProductUser(insertProductApplyFlowPO, channelUserRegisterPO.getId());

        //  主体-单次计费业务
        RespPlatformPhoneMd5DataExchange apiPlatFormDataExchange = null;
        //  平台计划解析撞库成功时的单价
        if (hasPlatform) {
            apiPlatFormDataExchange = RespPlatformPhoneMd5DataExchange.parseByJson(productApplyFlowPO.getRespData());
        }
        BigDecimal originalPrice = hasPlatform ? apiPlatFormDataExchange.getPrice() : null;

        ProductAmountBO productAmountBO = new ProductAmountBO();
        productAmountBO.setProductId(productPlanPO.getLoanProductId());
        productAmountBO.setProductPlanId(productPlanPO.getId());
        productAmountBO.setUserId(channelUserRegisterPO.getId());
        productAmountBO.setPhoneMd5(channelUserRegisterPO.getPhoneMd5());
        productAmountBO.setLoanChannelId(productApplyFlowPO.getLoanChannelId());
        productAmountBO.setApiClientId(productApplyFlowPO.getApiClientId());
        productAmountBO.setOriginalPrice(originalPrice);
        productAmountBO.setHasPlatform(hasPlatform);
        productAmountBO.setHasLocalExist(Boolean.FALSE);
        productAmountService.deduct(productAmountBO);
    }

}
